1、 I2C 框架
	I2C 框架包括以下几个部分：
	1） I2C 核心；管理 I2C 适配器驱动、 I2C 设备驱动、 I2C设备，此部分由 linux 提供
	2） I2C 适配器驱动；又叫 I2C 总线驱动，用于驱动 I2C 控制器，此部分由主控芯片厂家提供
	3） I2C 设备；又叫 I2C client ，用于描述 I2C 设备信息，一般在设备树中编写。
	4） I2C 设备驱动 ：又叫 i2c_driver ，用于驱动 I2C 设备，一般移植厂家驱动或自己编写
	5） I2C-dev ；将 I2C 总线虚拟成字符设备，使应用层能直接访问 I2C 总线，由 Linux 系统提供
2、 I2C 适配器
	对象 struct i2c_adapter 表示一个 I2C 适配器，其核心成员如下：
	//I2C 适配器操作函数集合
	const struct i2c_algorithm *algo;
	//适配器编号，使用 i2c_add_adapter 注册时由系统自动分配
	int nr;
	//超时时间
	int timeout;
	//重试次数
	int retries;
	//class 表示该 I2C bus 支持哪些类型的 I2C 从设备，部分驱动程序会检查该成员以确保适配器能操作设备
	//具体的类型包括：
	//    I2C_CLASS_HWMON :硬件监控类，如lm_sensors等；
	//    I2C_CLASS_DDC :DDC是数字显示通道（Digital Display Channel）的意思，通常用于显示设备信息的获取；
	//    I2C_CLASS_SPD :存储类的模组；
	//    I2C_CLASS_DEPRECATED :不支持自动探测。
	unsigned int class;
	//适配器的名字
	char name[48];
	//该适配器设备对应的 device ，其中 of_node 节点用于解析设备树中的 I2C 设备节点
	struct device dev;
	如下是向系统添加和删除 I2C 适配器的函数：
	//添加 I2C 适配器驱动，其中 i2c_add_numbered_adapter 需要静态指定编号，适配器添加成功后会自动解析相应设备
	//树节点下的子节点，并将其转换为 struct i2c_client 对象
	int i2c_add_adapter(struct i2c_adapter *adapter)
	int i2c_add_numbered_adapter(struct i2c_adapter *adap)
	//删除 I2C 适配器驱动
	void i2c_del_adapter(struct i2c_adapter * adap)
3、 I2C 设备
	对象 struct i2c_client 表示一个 I2C 设备，它用来描述的是 I2C 设备的信息，类似于 platform 总线的 struct 
platform_device ，其核心成员如下：
	//从机地址
	unsigned short addr;
	//名称
	char name[I2C_NAME_SIZE];
	//设备所使用的 I2C 适配器
	struct i2c_adapter *adapter;
	//继承的 device 对象
	struct device dev;
	//中断资源，iic匹配时会获取设备树描述的中断
	int irq;
	在驱动中通常通过设备树来描述一个 i2c_client 
	也可以使用下列函数创建一个 i2c_client ：
	struct i2c_adapter *i2c_get_adapter(int nr)
	struct i2c_client *i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
	对应的反操作函数如下：
	void i2c_unregister_device(struct i2c_client *client)
	void i2c_put_adapter(struct i2c_adapter *adap)
3、 I2C 驱动
	对象 struct i2c_driver 表示一个 I2C 设备驱动，它用来描述的是 I2C 设备的驱动信息，类似于 platform 总线的 
struct platform_driver ，其核心成员如下：
	//设备和驱动匹配成功执行函数
	int (*probe)(struct i2c_client *, const struct i2c_device_id *);
	//设备或驱动匹配卸载执行函数
	int (*remove)(struct i2c_client *);
	//继承 device_driver
	struct device_driver driver;
	//传统的 ID 匹配表，即使使用设备树后此参数也不能为NULL
	const struct i2c_device_id *id_table;
	如下是向系统添加和删除 I2C 设备驱动的函数：
	//注册 I2C 设备驱动
	int i2c_add_driver(struct i2c_driver *driver)
	//注销 I2C 设备驱动
	void i2c_del_driver(struct i2c_driver *driver)
4、 I2C 数据包
	在 I2C 设备框架中使用 struct i2c_msg 数组来描述 I2C 适配器要传输的数据，其主要成员如下：
	//从机地址
	__u16 addr;
	//传输标志，有如下标志：
	//    I2C_M_RD ：从从机读数据
	//    I2C_M_TEN ：地址长度为10位
	//    I2C_M_DMA_SAFE ：缓冲区支持 DMA
	//    I2C_M_RECV_LEN ：接收的第一个 byte 表示长度
	//    I2C_M_NO_RD_ACK ：不产生 ACK
	//    I2C_M_IGNORE_NAK ：忽略 NAK
	//    I2C_M_NOSTART ：不产生开始信号
	//    I2C_M_STOP ：产生停止信号
	_u16 flags;
	//消息长度
	__u16 len;
	//消息缓冲区
	__u8 *buf;
	I2C 设备可以使用下列函数发送数据包：
	/**
	 * adap I2C 适配器
	 * msgs msg 列表
	 * num msg 数量，或者说msgs数组的元素个数
	 * 返回负值失败，返回其他非负值，发送的 msgs 数量
	 * 此函数在连续发送多个数据包时如果设置了 I2C_M_NOSTART ，在发送数据包的最后 1byte 时不会等待 ACK 信号，
	 * 可能会导致发送失败
	 */
	int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
5、 I2C 设备和驱动匹配过程
	如下是 I2C 设备和驱动的匹配函数：
	static int i2c_device_match(struct device *dev, struct device_driver *drv)
	{
		struct i2c_client *client = i2c_verify_client(dev);
		struct i2c_driver *driver;

		/* 使用设备树进行匹配，如果 i2c_client 没有设备树节点则使用驱动的 of_match_table 与 i2c_client 的 
		name 进行比较 */
		if (i2c_of_match_device(drv->of_match_table, client))
			return 1;
	
		/* 使用 ACPI 进行匹配 */
		if (acpi_driver_match_device(dev, drv))
			return 1;

		driver = to_i2c_driver(drv);
	
		/* 使用 id_table 与 i2c_client 的 name 进行匹配 */
		if (i2c_match_id(driver->id_table, client))
			return 1;

		return 0;
	}
6、 I2C 设备树
	在那条 I2C 总线下挂载设备就在那条总线的设备树节点下添加对应设备的子节点，节点命名规则 [标签:]名称[@地址]，
节点内容必须包含 reg 属性和 compatible 属性， reg 属性用于描述设备地址， compatible 属性用于设备和驱动的匹配，
如下是在 i2c5 中添加一个 ap3216c 设备节点的示例。
	&i2c5 {
		//描述I2C控制器引脚，并使能I2C控制器
		pinctrl-names = "default", "sleep";
		pinctrl-0 = <&i2c5_pins_a>;
		pinctrl-1 = <&i2c5_pins_sleep_a>;
		status = "okay";

		//描述ap3216c设备
		ap3216c@1e {
			compatible = "alientek,ap3216c";
			reg = <0x1e>;
		};
	};
